package javax.xml.parsers;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.validation.Schema;
import org.xml.sax.HandlerBase;
import org.xml.sax.InputSource;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;


/**
 * 定义包装{@link org.xml.sax.XMLReader}实现类的API
 *  在JAXP 1.0中，这个类包装了{@link org.xml.sax.Parser}接口，
 *  但是该接口被替换为{@link org.xml.sax.XMLReader}。
 *  为了便于过渡，这个类继续支持相同的名称和接口以及支持新方法。
 *
 * 该实例类可以通过方法{@link javax.xml.parsers.SAXParserFactory#newSAXParser()} 获得。
 *
 * 一旦获得此类的实例，就可以从各种输入源分析XML。
 * 这些输入源可以是输入流，文件，URL和SAX输入源。

 * 此静态方法基于系统属性设置创建新的工厂实例，如果没有定义属性，则使用平台默认值.
 *
 */
public abstract class SAXParser {

    private static final boolean DEBUG = false;

    /**
     * <p>受保护的构造函数以防止实例化。
     * 实例化使用 {@link javax.xml.parsers.SAXParserFactory#newSAXParser()}.</p>
     */
    protected SAXParser () {

    }

    /**
     * 将此SAXParser重置为其原始配置
     *
     * SAXParser重置为@link SAXParserFactory#newSAXParser()}创建时相同的状态。
     * reset（）旨在允许重复使用现有的SAXParsers，从而节省与创建新SAXParser相关的资源。
     *
     * 重置SAXParser不保证具有相同的{@link Schema}
     * <code>Object</code>, e.g. {@link Object#equals(Object obj)}.
     * 它保证在功能上相等D
     * <code>Schema</code>.</p>
     *
     * @since 1.5
     */
    public void reset() {

        // implementors should override this method
        throw new UnsupportedOperationException(
            "This SAXParser, \"" + this.getClass().getName() + "\", does not support the reset functionality."
            + "  Specification \"" + this.getClass().getPackage().getSpecificationTitle() + "\""
            + " version \"" + this.getClass().getPackage().getSpecificationVersion() + "\""
            );
    }

    /**
     * 建议使用此方法的默认处理程序版本，因为处理程序基类已在SAX 2.0中弃用
     *
     * @param is 包含要解析的内容的输入流
     * @param hb SAX Handler Base使用
     *
     * @throws IllegalArgumentException:非法参数异常如果给定的输入流为空
     * @throws SAXException :如果解析产生SAX错误。
     * @throws IOException 如果发生与输入流交互的IO错误.
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(InputStream is, HandlerBase hb)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputStream cannot be null");
        }

        InputSource input = new InputSource(is);
        this.parse(input, hb);
    }

    /**
     * @param is 包含要解析的内容的输入流
     * @param hb SAX Handler Base使用
     * @param systemId：解析相对URI所需的系统ID
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler version of this method instead.
     */
    public void parse(
        InputStream is,
        HandlerBase hb,
        String systemId)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputStream cannot be null");
        }

        InputSource input = new InputSource(is);
        input.setSystemId(systemId);
        this.parse(input, hb);
    }

    /**
     * @param is 包含要解析的内容的输入流
     * @param dh 要使用的SAX默认处理程序
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(InputStream is, DefaultHandler dh)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputStream cannot be null");
        }

        InputSource input = new InputSource(is);
        this.parse(input, dh);
    }

    /**
     * Parse the content of the given {@link java.io.InputStream}
     * instance as XML using the specified
     * {@link org.xml.sax.helpers.DefaultHandler}.
     *
     * @param is 含要解析的内容的输入流
     * @param dh 使用的SAX默认处理程序。
     * @param systemId 解析相对URI所需的系统ID。
     *
     *  @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler version of this method instead.
     */
    public void parse(
        InputStream is,
        DefaultHandler dh,
        String systemId)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputStream cannot be null");
        }

        InputSource input = new InputSource(is);
        input.setSystemId(systemId);
        this.parse(input, dh);
    }

    /**
     *
     * @param uri 要解析的内容的位置。
     * @param hb SAX Handler Base使用
     *
     *  @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(String uri, HandlerBase hb)
        throws SAXException, IOException {
        if (uri == null) {
            throw new IllegalArgumentException("uri cannot be null");
        }

        InputSource input = new InputSource(uri);
        this.parse(input, hb);
    }

    /**
     * @param uri 要解析的内容的位置。
     * @param dh 要使用的SAX默认处理程序
     *
     *  @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(String uri, DefaultHandler dh)
        throws SAXException, IOException {
        if (uri == null) {
            throw new IllegalArgumentException("uri cannot be null");
        }

        InputSource input = new InputSource(uri);
        this.parse(input, dh);
    }

    /**
     * @param f 含要解析的XML的文件
     * @param hb The SAX HandlerBase to use.
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(File f, HandlerBase hb)
        throws SAXException, IOException {
        if (f == null) {
            throw new IllegalArgumentException("File cannot be null");
        }

        String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());

        if (DEBUG) {
            System.out.println("Escaped URI = " + escapedURI);
        }

        InputSource input = new InputSource(escapedURI);
        this.parse(input, hb);
    }

    /**
     * @param f 包含要解析的XML的文件
     * @param dh The SAX DefaultHandler to use.
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(File f, DefaultHandler dh)
        throws SAXException, IOException {
        if (f == null) {
            throw new IllegalArgumentException("File cannot be null");
        }

        String escapedURI = FilePathToURI.filepath2URI(f.getAbsolutePath());

        if (DEBUG) {
            System.out.println("Escaped URI = " + escapedURI);
        }

        InputSource input = new InputSource(escapedURI);
        this.parse(input, dh);
    }

    /**
     * @param is 包含要解析的内容的输入源。
     * @param hb The SAX HandlerBase to use.
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(InputSource is, HandlerBase hb)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputSource cannot be null");
        }

        Parser parser = this.getParser();
        if (hb != null) {
            parser.setDocumentHandler(hb);
            parser.setEntityResolver(hb);
            parser.setErrorHandler(hb);
            parser.setDTDHandler(hb);
        }
        parser.parse(is);
    }

    /**
     * Parse the content given {@link org.xml.sax.InputSource}
     * as XML using the specified
     * {@link org.xml.sax.helpers.DefaultHandler}.
     *
     * @param is 包含要解析的内容的输入源
     * @param dh The SAX DefaultHandler to use.
     *
     * @throws IllegalArgumentException：非法参数异常如果给定的输入流为空
     * @throws IOException 如果发生与输入流交互的任何IO错误
     * @throws SAXException 如果在处理过程中发生任何SAX错误。
     *
     * @see org.xml.sax.DocumentHandler
     */
    public void parse(InputSource is, DefaultHandler dh)
        throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException("InputSource cannot be null");
        }

        XMLReader reader = this.getXMLReader();
        if (dh != null) {
            reader.setContentHandler(dh);
            reader.setEntityResolver(dh);
            reader.setErrorHandler(dh);
            reader.setDTDHandler(dh);
        }
        reader.parse(is);
    }

    /**
     * 返回由此类的实现封装的SAX解析器
     *
     * @return 该类的实现封装的SAX解析器。
     *
     * @throws SAXException 如果在处理期间发生任何SAX错误。
     */
    public abstract org.xml.sax.Parser getParser() throws SAXException;

    /**
     *
     * @return 由此类的实现封装的XMLReader。
     *
     * @throws SAXException 如果在处理期间发生任何SAX错误。
     */

    public abstract org.xml.sax.XMLReader getXMLReader() throws SAXException;

    /**
     * 指示此分析器是否配置为了解命名空间。
     *
     * @return 果此分析器配置为了解命名空间，则为true; 否则为假。
     */

    public abstract boolean isNamespaceAware();

    /**
     * 示此分析器是否配置为验证XML文档
     *
     * @return 如果此分析器配置为验证XML文档，则为true; 否则为假
     */

    public abstract boolean isValidating();

    /**
     *
     *
     * @param name 要设置的属性的名称
     * @param value 要设置的属性的值
     *
     * @throws SAXNotRecognizedException AX未识别异常当底层XMLReader不能识别属性名称时
     * @throws SAXNotSupportedException SAX不支持的异常当底层XMLReader识别属性名称但不支持该属性时
     *
     * @see org.xml.sax.XMLReader#setProperty
     */
    public abstract void setProperty(String name, Object value)
        throws SAXNotRecognizedException, SAXNotSupportedException;

    /**
     * @param name 要检索的属性的名称。
     * @return 请求属性的值
     *
     * @throws SAXNotRecognizedException AX未识别异常当底层XMLReader不能识别属性名称时
     * @throws SAXNotSupportedException SAX不支持的异常当底层XMLReader识别属性名称但不支持该属性时
     *
     * @see org.xml.sax.XMLReader#getProperty
     */
    public abstract Object getProperty(String name)
        throws SAXNotRecognizedException, SAXNotSupportedException;

    /**
     *获取XML处理器正在使用的{@link Schema}的引用
     *
     * @return {@link Schema} 若没有引用，返回null
     *
     * @throws UnsupportedOperationException
     *      支持的操作异常为了向后兼容，当使用早期版本的JAXP实现时，将引发此异常
     *
     * @since 1.5
     */
    public Schema getSchema() {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }

    /**
     * 获取此解析器的XInclude处理模式
     * @return
     *      the return value of
     *      the {@link SAXParserFactory#isXIncludeAware()}
     *      when this parser was created from factory.
     *当从工厂创建此解析器时，{@link SAXParserFactory#isXIncludeAware()}的返回值
     * @throws UnsupportedOperationException
     *      不支持的操作异常为了向后兼容，当使用早期版本的JAXP实现时，将引发此异常。
     *
     * @since 1.5
     *
     * @see SAXParserFactory#setXIncludeAware(boolean)
     */
    public boolean isXIncludeAware() {
        throw new UnsupportedOperationException(
            "This parser does not support specification \""
            + this.getClass().getPackage().getSpecificationTitle()
            + "\" version \""
            + this.getClass().getPackage().getSpecificationVersion()
            + "\""
            );
    }
}
